﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SharpCmd.Controls;
using SharpCmd.Controls.Viewers;
using SharpCmd.Dialogs.PanelActions;
using SharpCmd.IO;

namespace SharpCmd
{
    internal partial class MainForm : Form
    {
        #region fields
        private CheatHandler cheatHandler;
        #endregion

        #region ctor
        public MainForm()
        {
            InitializeComponent();
            RestorePanels();
            Instance = this;
            cheatHandler = new CheatHandler();
        }
        #endregion

        public static MainForm Instance { get; private set; }

        #region fields
        public DirectoryViewPanel ActiveDirectoryViewPanel { get; private set; }
        #endregion fields

        private void MainForm_Load(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.DoFocus();
        }

        #region DirectoryViewPanels handling
        private DirectoryViewPanel InactiveDirectoryViewPanel
        {
            get { return dvpLeft == ActiveDirectoryViewPanel ? dvpRight : dvpLeft; }
        }

        private void DirectoryViewPanel_Enter(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel = sender as DirectoryViewPanel;
            ActivatePanel();
        }

        private void RestorePanels()
        {
            ActiveDirectoryViewPanel = dvpLeft;
            dvpLeft.ViewType = PanelViewType.Full;
			dvpRight.ViewType = PanelViewType.Full;
#if OSX
			dvpLeft.Path = dvpRight.Path="/";
#else
            dvpLeft.Path = @"c:\";
			dvpRight.Path = @"c:\";
#endif
            Console.WriteLine ("test");
            ActivatePanel();
        }

        private void ActivatePanel()
        {
            ActiveDirectoryViewPanel.Active = true;
            InactiveDirectoryViewPanel.Active = false;
            ActiveDirectoryViewPanel.DoFocus();
        }
        #endregion

        #region layouts
        private void ToolStripBottom_Layout(object sender, LayoutEventArgs e)
        {
            //resize buttons
            const int BUTTON_COUNT = 6; // F3,F4,F5,F6,F7,F8
            var usedWidth = toolStripBottom.Items.OfType<ToolStripSeparator>().Sum(p => p.Width + 1);
            int buttonWidth = (toolStripBottom.ClientSize.Width - usedWidth) / BUTTON_COUNT;
            toolStripBottom.Items.OfType<ToolStripButton>().ToList().ForEach(p => p.Width = buttonWidth);
        }

        private void ToolStripCmd_Layout(object sender, LayoutEventArgs e)
        {
            const double TEXT_BOX_SIZE = 0.65;
            tbCmd.Width = (int)(toolStripCmd.Width * TEXT_BOX_SIZE);
        }
        #endregion

        #region toolstrip button handlers
        #region File
        private void MenuFileProperties_Click(object sender, EventArgs e)
        {
            throw new NotImplementedException();
        }

        private void MenuFileExit_Click(object sender, EventArgs e)
        {
            Close();
        }
        #endregion

        private void newTabToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.OpenNewTab();
        }

        #region Configuration
        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Options form");
        }
        #endregion

        #region Select
        private void MenuSelectSelectGroup_Click(object sender, EventArgs e)
        {
            var f = new Dialogs.Select.ExpandSelectionForm();
            if (f.ShowDialog() != DialogResult.OK)
                return;
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.Select(f.Mask); //TODO get select group from dialog
        }

        private void MenuSelectUnselectGroup_Click(object sender, EventArgs e)
        {
            var f = new Dialogs.Select.ExpandSelectionForm();
            f.Text = "Shrink selection";
            if (f.ShowDialog() != DialogResult.OK)
                return;
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.UnSelect(f.Mask); //TODO get unselect group from dialog
        }

        private void MenuSelectSelectAll_Click(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectAll();
        }

        private void MenuSelectInvertSelection_Click(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.InvertSelection();
        }

        private void MenuSelectSelectSameExtension_Click(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectSameExtension();
        }

        private void copySelectedNamesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectedItemInfos.ForEach(p => sb.AppendLine(p.Name));
            Clipboard.SetText(sb.ToString());
        }

        private void CopyNamesWithPath()
        {
            StringBuilder sb = new StringBuilder();
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectedItemInfos.ForEach(p => sb.AppendLine(p.FullName));
            Clipboard.SetText(sb.ToString());
        }

        private void copyNamesWithpathToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CopyNamesWithPath();
        }

        private void copyWithAlldetailsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectedItemInfos.ForEach(p => sb.AppendLine(p.FullDetails));
            Clipboard.SetText(sb.ToString());
        }

        private void copyWithPathdetailsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectedItemInfos.ForEach(p => sb.AppendLine(p.FullDetailsFullPath));
            Clipboard.SetText(sb.ToString());
        }

        private void pathToCommandlineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddTextToCmdBox(GetSelectedItemName());
        }

        private void fullPathToCommandLineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddTextToCmdBox(GetSelectedItemFullName());
        }
        #endregion

        #region Commands
        private void opencmdShellHereToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start("cmd", string.Format("/k cd \"{0}\"", ActiveDirectoryViewPanel.Path));
        }

        private void goToDesktopToolStripMenuItem_Click(object sender, EventArgs e)
        {
#if OSX
#else
            Shell32.Shell shell = new Shell32.ShellClass();
            shell.ToggleDesktop();
#endif
        }

        private void switchSidesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string temp = dvpLeft.ActiveFileSystemViewer.Path;
            dvpLeft.ActiveFileSystemViewer.Path = dvpRight.ActiveFileSystemViewer.Path;
            dvpRight.ActiveFileSystemViewer.Path = temp;
        }
        #endregion

        #region Network
        private void connectNetworkShareToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SharpCmd.Dialogs.Standalone.NetworkShareDialogs.WNetConnectionDialog(this.Handle, SharpCmd.Dialogs.Standalone.NetworkShareDialogs.RESOURCETYPE_DISK);
        }

        private void disconnectNetworkShareToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SharpCmd.Dialogs.Standalone.NetworkShareDialogs.WNetDisconnectDialog(this.Handle, SharpCmd.Dialogs.Standalone.NetworkShareDialogs.RESOURCETYPE_DISK);
        }
        #endregion

        #region Display
        private void nameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.Sort(SharpCmd.Controls.FileSystemViewers.SortType.Name);
        }

        private void extensionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.Sort(SharpCmd.Controls.FileSystemViewers.SortType.Extension);
        }

        private void dateAndTimeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.Sort(SharpCmd.Controls.FileSystemViewers.SortType.Date);
        }

        private void sizeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.Sort(SharpCmd.Controls.FileSystemViewers.SortType.Size);
        }

        private void reverseOrderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            throw new NotImplementedException();
        }

        protected void OnReload(object sender, EventArgs e)
        {
            dvpLeft.Reload();
            dvpRight.Reload();
        }
        #endregion

        #region Help
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("SharpCmd - two window file manager\r\n2010 - Juraj Borza\r\nUnder BSD license\r\n\r\nUses GongShell library (http://gong-shell.sourceforge.net/)\r\n\r\nMany thanks to the stackoverflow community (http://stackoverflow.com)", "About SharpCmd", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        #endregion
        #endregion

        private void AddTextToCmdBox(string text)
        {
            tbCmd.Text += text;
        }

        #region Operations
        private void OnView(object sender, EventArgs e)
        {
            var file = GetSelectedItemInfo();
            if (file.Type == FSObjectType.Directory)
                return;
            ViewerForm viewer = new ViewerForm();
            // set viewer type according to the file type
            string[] images = { "png", "jpg", "jpeg", "bmp", "gif", "emf" };
            string[] soundVideo = { "avi", "mp3", "mp2", "mpg", "mpeg", "wmv", "wma", "wav", "mid" };
            string[] html = { "html", "htm", "xml" };
            viewer.ViewerType = ViewerType.Text;
            foreach (string imgExt in images)
            {
                if (file.Extension.ToLower() == imgExt)
                {
                    viewer.ViewerType = ViewerType.Image;
                    break;
                }
            }
            foreach (string imgExt in soundVideo)
            {
                if (file.Extension.ToLower() == imgExt)
                {
                    viewer.ViewerType = ViewerType.Media;
                    break;
                }
            }
            foreach (string imgExt in html)
            {
                if (file.Extension.ToLower() == imgExt)
                {
                    viewer.ViewerType = ViewerType.Html;
                    break;
                }
            }
            viewer.SelectedFile = file.FullName;
            viewer.ShowViewer();
            viewer.Show();
        }

        private void OnEdit(object sender, EventArgs e)
        {
            //TODO 0.20 read editor name from configuration
            Process.Start("notepad.exe", GetSelectedItemFullName());
        }

        private void OnCopy(object sender, EventArgs e)
        {
            //build copy form
            CopyPrepareForm prepForm = new CopyPrepareForm(CopyFormType.Move);
            prepForm.TargetDirectory = InactiveDirectoryViewPanel.Path;
            if (prepForm.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;
            //get all selected files
            var selectedInfos = GetSelectedItemInfos();
            CopyForm copyForm = new CopyForm(CopyFormType.Copy);
            copyForm.TargetDirectory = prepForm.TargetDirectory;
            copyForm.SourceDirectory = ActiveDirectoryViewPanel.Path;
            copyForm.Infos = selectedInfos;
            copyForm.Show();
        }

        private void OnMove(object sender, EventArgs e)
        {
            //build copy form
            CopyPrepareForm prepForm = new CopyPrepareForm(CopyFormType.Move);
            prepForm.TargetDirectory = InactiveDirectoryViewPanel.Path;
            if (prepForm.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;
            //get all selected files
            var selectedInfos = GetSelectedItemInfos();
            CopyForm copyForm = new CopyForm(CopyFormType.Move);
            copyForm.TargetDirectory = prepForm.TargetDirectory;
            copyForm.SourceDirectory = ActiveDirectoryViewPanel.Path;
            copyForm.Infos = selectedInfos;
            copyForm.Show();
        }

        private void OnNewDirectory(object sender, EventArgs e)
        {
            Dialogs.Common.CommonTextBoxForm f = new SharpCmd.Dialogs.Common.CommonTextBoxForm();
            if (IsSelectedItem())
                f.Value = GetSelectedItemName();
            if (f.ShowDialog() != DialogResult.OK)
                return;
            string newPath = Path.Combine(GetSelectedPath(), f.Value);
            Directory.CreateDirectory(newPath);
            OnReload(null, null);
            ActiveDirectoryViewPanel.ActiveFileSystemViewer.FocusItemWithPath(newPath);
        }

        private void OnDelete(object sender, EventArgs e)
        {
            DeletePrepareForm prepForm = new DeletePrepareForm();
            prepForm.Infos = GetSelectedItemInfos();
            if (prepForm.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;
            DeleteForm delForm = new DeleteForm();
            delForm.Infos = prepForm.Infos;
            delForm.Show();
        }

        private void OnRename(object sender, EventArgs e)
        {
            var info = GetSelectedItemInfo();
            if (info.Fake)
                return;
            RenameSingleFile f = new RenameSingleFile();
            f.OriginalFullName = info.FullName;
            f.ItemName = info.NameWithExtension;
            if (f.ShowDialog() != DialogResult.OK)
                return;
            //todo do rename
            if (info.Type == FSObjectType.File)
            {
                FileInfo fi = new FileInfo(info.FullName);
                if (FileCopier.RenameFile(info.FullName, Path.Combine(fi.DirectoryName, f.ItemName)))
                    Reload();
            }
            else if (info.Type == FSObjectType.Directory)
            {
                DirectoryInfo di = new DirectoryInfo(info.FullName);
                if (FileCopier.RenameDirectory(info.FullName, Path.Combine(di.Parent.FullName, f.ItemName)))
                    Reload();
            }
        }
        #endregion

        #region actions that can be called from lower classes (in GUI manner)
        public void ShowLeftPaneInRight()
        {
            ShowPaneInAnotherPane(dvpLeft, dvpRight);
        }

        public void ShowRightPaneInLeft()
        {
            ShowPaneInAnotherPane(dvpRight, dvpLeft);
        }

        private void ShowPaneInAnotherPane(DirectoryViewPanel source, DirectoryViewPanel destination)
        {
            var item = source.ActiveFileSystemViewer.FocusedItem;
            string newPath;
            if (item == null || item.Type == FSObjectType.File || source != ActiveDirectoryViewPanel)
                newPath = source.ActiveFileSystemViewer.Path;
            else
                newPath = item.FullName;
            destination.ActiveFileSystemViewer.Path = newPath;
        }
        #endregion

        #region input events
        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Alt)
            {
                switch (e.KeyCode)
                {
                    case Keys.F1:
                        dvpLeft.DropDownCombobox();
                        break;
                    case Keys.F2:
                        dvpRight.DropDownCombobox();
                        break;
                    case Keys.Add:
                        MenuSelectSelectSameExtension_Click(null, null);
                        return;
                }
            }
            if (e.Control)
            {
                switch (e.KeyCode)
                {
                    case Keys.Add:
                    case Keys.A:
                        MenuSelectSelectAll_Click(null, null);
                        return;
                }
            }
            switch (e.KeyCode)
            {
                case Keys.Add:
                    MenuSelectSelectGroup_Click(null, null);
                    return;
                case Keys.Subtract:
                    MenuSelectUnselectGroup_Click(null, null);
                    return;
                case Keys.Multiply:
                    MenuSelectInvertSelection_Click(null, null);
                    return;
            }
            cheatHandler.KeyPress((char)e.KeyValue);
        }

        //TODO implement meaningful cheat codes ;)
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            switch (msg.Msg)
            {
                case Windows.Events.WM_KEYDOWN:
                    //TODO process Ctrl+Tab and Ctrl+Shift+Tab too
                    if (msg.WParam.ToInt32() == (int)Keys.Tab)
                    {
                        ToggleActivePanel();
                        return true;
                    }
                    else if (msg.WParam.ToInt32() == (int)Keys.Escape)
                    {
                        ClearCmdTextBox();
                        return true;
                    }
                    else if (msg.WParam.ToInt32() == (int)Keys.Delete)
                    {
                        OnDelete(null, null);
                        return true;
                    }
                    break;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void ClearCmdTextBox()
        {
            tbCmd.Text = "";
        }

        private void ToggleActivePanel()
        {
            ActiveDirectoryViewPanel = ActiveDirectoryViewPanel == dvpLeft ? dvpRight : dvpLeft;
            ActiveDirectoryViewPanel.DoFocus();
        }
        #endregion input events

        #region selected items retrieval
        private bool IsSelectedItem()
        {
            return ActiveDirectoryViewPanel.ActiveFileSystemViewer.HasSelectedItem;
        }
        private string GetSelectedItemName()
        {
            return ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectedItem.NameWithExtension;
        }

        private FSObjectInfo GetSelectedItemInfo()
        {
            return ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectedItem;
        }

        private string GetSelectedItemFullName()
        {
            return ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectedItem.FullName;
        }

        private string GetSelectedPath()
        {
            return ActiveDirectoryViewPanel.ActiveFileSystemViewer.Path;
        }

        private List<FSObjectInfo> GetSelectedItemInfos()
        {
            return ActiveDirectoryViewPanel.ActiveFileSystemViewer.SelectedItemInfos;
        }
        #endregion

        private void tsbCopyNames_Click(object sender, EventArgs e)
        {
            CopyNamesWithPath();
        }

        internal void Reload()
        {
            OnReload(null, null);
        }

        private void newTabToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            ActiveDirectoryViewPanel.OpenNewTab();
        }
    }
}